package com.yangyang.ralearn.common.entity.base;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

import com.yangyang.ralearn.common.JEnvironment;
import com.yangyang.ralearn.common.types.JType;
import com.yangyang.ralearn.server.JSimulator;
import com.yangyang.ralearn.util.ArrayUtil;

public class BaseActionModelDef {

	protected String name;
	protected Map<String, JType> mapVar2Type;
	protected List<ParamedPredicate> preConditions;
	protected List<ParamedPredicate> effects;
	protected JEnvironment environment;
	private int QValue = 1000;// 当前Q值

	public String getName() {
		return this.name;
	}

	public int getQValue() {
		return this.QValue;
	}

	public void setQValue(int value) {
		this.QValue = value;
	}

	public BaseActionModelDef(JEnvironment environment, String name,
			Map<String, JType> mapVar2Type,
			List<ParamedPredicate> preConditions,
			List<ParamedPredicate> effects, boolean flag) {
		this.environment = environment;
		this.name = name;
		this.mapVar2Type = mapVar2Type;
		this.preConditions = new ArrayList<ParamedPredicate>();
		this.preConditions.addAll(preConditions);
		this.effects = new ArrayList<ParamedPredicate>();
		this.effects.addAll(effects);
	}

	public BaseActionModelDef(JEnvironment environment, String name,
			HashMap<String, String> parameter, List<String> preconditions,
			List<String> effects) {
		this.environment = environment;
		this.name = name;
		this.mapVar2Type = new LinkedHashMap<String, JType>();
		for (Entry<String, String> entry : parameter.entrySet()) {
			this.mapVar2Type.put(entry.getKey(),
					environment.mapNameType.get(entry.getValue()));
		}
		this.preConditions = new ArrayList<ParamedPredicate>();
		if (preconditions != null)
			for (String condition : preconditions) {
				String[] data = condition.split(" ");
				this.preConditions.add(new ParamedPredicate(environment,
						data[0], data.length < 2 ? null : ArrayUtil.subArray(
								data, 1, 0)));
			}
		this.effects = new ArrayList<ParamedPredicate>();
		if (effects != null)
			for (String condition : effects) {
				String[] data = condition.split(" ");
				this.effects
						.add(new ParamedPredicate(environment, data[0],
								data.length < 2 ? null : ArrayUtil.subArray(
										data, 1, 0)));
			}
	}

	public static boolean canDo(BaseAction action, BaseActionModelDef def,
			List<AbstractDomainPredicate> states) {
		if (def == null) {
			Logger.getLogger(JSimulator.class).error(
					"JSimulator.doaction action :" + action.getType()
							+ " has no default actionmodel");
			return false;
		}
		String[] variables = def.getParamDef().keySet().toArray(new String[0]);
		HashMap<String, String> mapVariableValues = new HashMap<String, String>();
		for (int i = 0; i < action.getValues().size(); i++) {
			mapVariableValues.put(variables[i], action.getValues().get(i)
					.getName());
		}
		for (ParamedPredicate pre : def.getPreConditions()) {
			if (!states.contains(pre.parsePredicate(mapVariableValues)))
				return false;
		}
		return true;
	}

	public static List<AbstractDomainPredicate> doAction(BaseAction action,
			BaseActionModelDef def) {
		List<AbstractDomainPredicate> effects = new ArrayList<AbstractDomainPredicate>();
		HashMap<String, String> mapVariableValues = new HashMap<String, String>();
		String[] variables = def.getParamDef().keySet().toArray(new String[0]);
		for (int i = 0; i < action.getValues().size(); i++) {
			mapVariableValues.put(variables[i], action.getValues().get(i)
					.getName());
		}
		for (ParamedPredicate pre : def.getEffects()) {
			AbstractDomainPredicate pred = pre
					.parsePredicate(mapVariableValues);
			effects.add(pred);
		}
		return effects;
	}

	/**
	 * @return the mPreConditions
	 */
	public List<ParamedPredicate> getPreConditions() {
		return preConditions;
	}

	/**
	 * @param mPreConditions
	 *            the mPreConditions to set
	 * 
	 *            public void setmPreConditions(List<String> mPreConditions) {
	 *            this.mPreConditions = mPreConditions; }
	 */

	/**
	 * @return the mEffects
	 */
	public List<ParamedPredicate> getEffects() {
		return effects;
	}

	/**
	 * @return the mParameters
	 */
	public Map<String, JType> getParamDef() {
		return mapVar2Type;
	}

	@Override
	public String toString() {
		return "BaseActionModelDef [mName=" + name + ", preConditions="
				+ preConditions + ", effects=" + effects + ", qvalue= "
				+ QValue + "]";
	}

	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return this.name.hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		// TODO Auto-generated method stub
		return super.equals(obj);
	}

	@Override
	protected Object clone() {
		// TODO Auto-generated method stub
		return new BaseActionModelDef(this.environment, this.name,
				this.mapVar2Type, this.preConditions, this.effects, true);
	}

}
